﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.IO;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Web.UI.WebControls.WebParts;
using up6.db.model;
using up7.db.biz;
using up7.db.model;
using up7.db.utils;
using up7.filemgr.app;

namespace up7.db
{
    public partial class f_post : WebBase
    {
        void send_error(string errCode, JObject par = null)
        {
            this.toContent(
                new JObject {
                    { "msg",errCode},
                    { "code",errCode},
                    { "md5","" },//文件块MD5
                    { "offset", -1 },//偏移
                    { "param", par},//参数信息
                });
            Response.End();
        }

        void validBlockMd5(Stream s,FileInf f) {
            //未开启 MD5验证
            if (string.IsNullOrEmpty(f.blockMd5)) return;
            string md5Svr = Md5Tool.calc(s);
            if(md5Svr != f.blockMd5)
            {
                this.send_error(UploadErrorCode.blockMd5Different,
                    new JObject {
                            { "md5Svr",md5Svr },
                            { "md5Loc",f.blockMd5 }
                        });
            }
        }

        void validBlockSize(Stream s,FileInf f) { 
            if(s.Length!=f.blockSize)
            {
                this.send_error(UploadErrorCode.blockSizeDifferent,
                    new JObject {
                            { "sizeRecv",s.Length},
                            { "sizeSend",f.blockSize}
                        });
            }
        }

        /// <summary>
        /// 解压
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        Stream unCompress(FileInf f, Stream s) {
            //未启用压缩
            if (f.blockSizeCpr==0) return s;

            if(f.blockSizeCpr != s.Length)
            {
                this.send_error(UploadErrorCode.blockSizeCprDifferent,
                    new JObject { 
                        { "CompressSizeLoc",f.blockSizeCpr} ,
                        { "CompressSizeSvr",s.Length} ,
                    });
            }
            return UtilsTool.unCompress(s, f.blockCompressType);
        }

        Stream unEncrypt(FileInf f, Stream s)
        {
            //未加密
            if (f.blockSizeCry == 0) return s;
            //块大小不相同
            if (f.blockSizeCry != s.Length)
            {
                this.send_error(UploadErrorCode.blockSizeCryDifferent,
                new JObject {
                                {"blockSizeCryRecv",s.Length},
                                {"blockSizeCrySend",f.blockSizeCry},
                    });
            }

            //加密存储
            if (f.encrypt) return s;

            CryptoTool ct = new CryptoTool();
            s = ct.decode(f.encryptAlgorithm, s);
            return s;
        }

        /// <summary>
        /// 接收文件块数据并写入到目标文件中
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Page_Load(object sender, EventArgs e)
        {
            //无文件数据
            if (Request.Files.Count < 1)
            {
                this.send_error("block empty");
                return;
            }

            FileInf fileSvr = new FileInf();
            fileSvr.id = this.headStr("id");
            fileSvr.pid = this.headStr("pid");
            fileSvr.pidRoot = this.headStr("pidRoot");
            fileSvr.perSvr = this.headStr("perSvr");
            fileSvr.lenLoc = this.headLong("lenLoc");
            fileSvr.lenSvr = this.headLong("lenSvr");
            fileSvr.sizeLoc = this.headStr("sizeLoc");
            fileSvr.blockOffset = this.headLong("blockOffset");
            fileSvr.blockIndex = this.headInt("blockIndex");
            fileSvr.blockCount = this.headInt("blockCount");
            fileSvr.blockSize = this.headInt("blockSize");
            fileSvr.blockEncrypt = this.headBool("blockEncrypt");
            fileSvr.blockSizeCry = this.headInt("blockSizeCry");
            fileSvr.blockSizeCpr = this.headInt("blockSizeCpr");
            fileSvr.blockMd5 = this.headStr("blockMd5");
            fileSvr.blockCompress = this.headBool("blockCompress");
            fileSvr.blockCompressType = this.headStr("blockCompressType");
            fileSvr.object_id = this.headString("object_id");//
            fileSvr.encryptAlgorithm = this.headString("blockEncryptAgo");//

            fileSvr.pathSvr = Request.Form["pathSvr"];//
            fileSvr.pathRel = Request.Form["pathRel"];//parentDir/filename.ext
            fileSvr.pathLoc = Request.Form["pathLoc"];

            //fileSvr.nameLoc = PathTool.url_decode(fileSvr.nameLoc);
            fileSvr.pathLoc = PathTool.url_decode(fileSvr.pathLoc);
            fileSvr.pathSvr = PathTool.url_decode(fileSvr.pathSvr);
            fileSvr.pathRel = PathTool.url_decode(fileSvr.pathRel);
            fileSvr.nameLoc = PathTool.getName(fileSvr.pathLoc);
            fileSvr.nameSvr = fileSvr.nameLoc;

            //检查变量
            if (string.IsNullOrEmpty(fileSvr.id)|| 
                string.IsNullOrEmpty(fileSvr.nameLoc) ||
                string.IsNullOrEmpty(fileSvr.pathLoc) ||
                string.IsNullOrEmpty(fileSvr.pathSvr))
            {
                var pars = new JObject {
                    { "lenLoc",fileSvr.lenLoc},
                    { "uid",fileSvr.uid},
                    { "nameLoc",fileSvr.nameLoc},
                    { "pathLoc",fileSvr.pathLoc},
                    { "pidRoot",fileSvr.pidRoot},
                    { "id",fileSvr.id},
                };
                this.toContent(pars, 500);
                return;
            }

            HttpPostedFile part = Request.Files.Get(0);
            var stm = part.InputStream;

            //验证文件块MD值
            this.validBlockMd5(stm, fileSvr);

            //解压
            stm = this.unCompress(fileSvr, stm);
            
            //解密
            stm = this.unEncrypt(fileSvr, stm);

            //验证块大小
            this.validBlockSize(stm, fileSvr);
            
            PathBuilder pb = new PathBuilder();
            fileSvr.pathSvr = pb.relToAbs(fileSvr.pathSvr);

            try
            {
                //保存块数据
                FileBlockWriter fw = new FileBlockWriter();
                if (1 == fileSvr.blockIndex) fw.make(fileSvr);
                if (1 == fileSvr.blockIndex) fileSvr.object_id = "oss.id";

                fw.write(fileSvr, stm);
            }
            catch (IOException ie)
            {
                this.send_error(UploadErrorCode.writeBlockDataFail,
                    new JObject { { "exception", ie.Message } });
            }

            //触发事件
            up7_biz_event.file_post_block(fileSvr.id, fileSvr.blockIndex);

            //返回信息
            JObject o = new JObject();
            o["msg"] = "ok";
            o["offset"] = fileSvr.blockOffset;
            //回传给控件
            if (fileSvr.blockIndex == 1) 
                o["fields"] = new JObject {
                    { "object_id", fileSvr.object_id}
                };
            this.toContentJson(o);
        }
    }
}